from django.utils.safestring import mark_safe
import copy
'''
使用分页需要执行：
A 在视图函数
def customer_list(request):
    # 1 在数据库查询数据
    queryset = models.Customer.objects.filter(active=1).select_related("level","creator" )
    # 2 把查询到的内容给到Pagination
    obj = Pagination(request = request,queryset = queryset) #实例化页码类
    context = {
        "queryset": queryset[obj.start:obj.end],  # 切片显示前5个数据
        "pager_string": obj.html(),#生成html代码的页码函数
    }
    #给到前端页面
    return render(request, "customer_list.html",context)

B 在html页面上
    表格
    {% for row in queryset %}
{#    每次渲染界面时 加个行号#}
        <tr row-id="{{ row.id }}">
            <td>{{ row.id }}</td>
            <td>{{ row.username }}</td>
            <td>{{ row.mobile }}</td>
    {% endfor %}
     {#分页功能    #}
    <ul class="pagination">
        {{ pager_string }}
    </ul>
    
    
#升级版本
A 在视图函数
def customer_list(request):
    # 1 在数据库查询数据
    queryset = models.Customer.objects.filter(active=1).select_related("level","creator" )
    # 2 把查询到的内容给到Pagination
    
    pager = Pagination(request=request, query_set=queryset)  # 实例化页码类
    #给到前端页面
     return render(request, "customer_list.html", {"pager":pager})
    
B 在html页面上
    表格
    {% for row in pager.queryset %}
{#    每次渲染界面时 加个行号#}
        <tr row-id="{{ row.id }}">
            <td>{{ row.id }}</td>
            <td>{{ row.username }}</td>
            <td>{{ row.mobile }}</td>
    {% endfor %}
    
     {#分页功能    #}
    <ul class="pagination">
        {{ pager.html }} #方法调用
    </ul>
    
'''



#封装页码方法
class Pagination:
    # 传request为了方便处理当用户传入的：http://localhost:8000/customer/list/?page=1
    #page第几页 page为负数或其他异常值时的异常处理
    # query_set数据库获取的数据类
    def __init__(self,request,query_set,per_page_count=5):
        self.request = request
        self.query_dict = copy.deepcopy(self.request.GET) #拷贝数据，用于后续加减数据
        self.query_dict._mutable = True #设置query_dict可修改
        self.query_set = query_set
        self.total = query_set.count()  # 获取总数据个数
        # 3.1计算分多少页：使用divmod(数据个数，每页多少个）=》（满足每页多少个条件的页数,最后一页还有多少数据）
        self.total_page, self.div = divmod(self.total, per_page_count)
        # 如果 div有值 页码需要添加一页
        if self.div:
            self.total_page += 1

        self.page = self.page_error() # 当前访问的页码
        self.per_page_count = per_page_count # 页面数据显示个数
        # 1页从那个数据开始显示到那个数据结束
        self.start = (self.page - 1) * per_page_count  # 当前页开始显示的数据位置 （页面号-1 ）* 页面数据个数
        self.end = per_page_count * self.page  # 当前页结束数据位置


    #页码异常情况处理
    def page_error(self):
        page = self.request.GET.get('page')  # 获取传输来的页面参数(当前访问的页面）
        if not page: # 如果没有传页码
            page = 1
        else:
            #如果不是数值 固定为1
            if not page.isdecimal():
                page = 1
            else:
                page = int(page)
                if page <= 0: #页码不能小于等于0
                    page = 1
                else:
                    if page>self.total_page: #页码不能大于最大值
                        page = self.total_page
        return page

    # 生成html页码函数
    def html(self):
        #没数据不显示页码
        if not self.total:
            return ""

        # 3 编写分页html页码
        pager_list = []  # html列表
        # 3.2 页码少都显示，页码多面只展示当前选中前后相关的5页
        if self.total_page <= 10:  # 页码小于10页，
            start_page = 1  # 开始页
            end_page = self.total_page  # 结束页
        else:
            # 判断当前页：处理最小值： 小于=6 ：开始位置就是1 不能小于1
            if self.page <= 6:
                start_page = 1  # 开始页
                end_page = 10  # 结束页
            else:
                # 处理最大值：当页码后5页大于最大值就不加
                if self.page + 5 > self.total_page:
                    start_page = self.total_page - 10  # 开始的页码为最大值-10 的页码
                    end_page = self.total_page  # 最后的页码为最大值
                else:  # 否则生成当前页的前后5页
                    start_page = self.page - 5  # 开始页
                    end_page = self.page + 5  # 结束页
        self.query_dict.setlist("page",[1]) #向request.GET里面加一个值page
        param_str = self.query_dict.urlencode() #转字符串 url前面附带的参数&page=1
        pager_list.append(f'<li><a href="?{param_str}">首页</a></li>') #首页
        if self.page > 1: #页码大于1 才显示
            self.query_dict.setlist("page", [self.page-1])#向request.GET里面改值page 的参数
            pager_list.append(f'<li><a href="?{self.query_dict.urlencode()}">上页</a></li>')
        # 循环生成html页码
        for i in range(start_page, end_page + 1):
            if i == self.page:
                self.query_dict.setlist("page", [i])
                item = f'<li class="active"><a href="?{self.query_dict.urlencode()}">{i}</a></li>'  # 加一个选中的样式
            else:
                self.query_dict.setlist("page", [i])
                item = f'<li><a href="?{self.query_dict.urlencode()}">{i}</a></li>'
            pager_list.append(item)
        if self.page < self.total_page:  # 页码小于最大页码 才显示
            self.query_dict.setlist("page", [self.page+1])
            pager_list.append(f'<li><a href="?{self.query_dict.urlencode()}">下页</a></li>')
        #尾页
        self.query_dict.setlist("page", [self.total_page])
        pager_list.append(f'<li><a href="?{self.query_dict.urlencode()}">尾页</a></li>')
        # 显示多少条多少页提示 class="disabled"不可选
        pager_list.append(f'<li class="disabled" ><a>数据共{self.total}条{self.total_page}页</a></li>')
        # 拼接为字符串给前端 注意：因为防XSS攻击机制直接传输HTML代码界面会以字符串显示 需要mark_safe处理
        pager_string = mark_safe(''.join(pager_list))
        return pager_string

    #返回切片以后的数据库数据
    def queryset(self):
        if self.total:
            return self.query_set[self.start:self.end]
        #没数据不切片
        return self.query_set